{
	import ir.*;
	import ir.blocks.*;
	import java.util.*;
}
/*****************************************************************************
	Swarm Tree Parser (The TreeWalker)
	tc2165: 11/2/07:
		pending:
		- finish the walk [ok]
		- actually make the walk generate an IR structure [ok, primitively sofar]
		- execute bindings [ok]
		- "hello world" [done, primitively 11/22/07]
		- general Bindables (unit, facetblock)
		- Stmt do general structures
*****************************************************************************/

class SwarmWalker extends TreeParser;

options {
	importVocab=Swm;
}

/* Setup the Program: build dictionary, init MAIN cell */
{
	//HashMap<String, CellDef> dict = new HashMap<String, CellDef>();
	
	CellDef main = new CellDef("MAIN");
}

/* Files: a sequence of cell declarations (must include a MAIN cell) */
file returns [CellDef main] {
		CellDef a;
		main = null;
	// add to a data struct ArrayList<Named> for Named interface (implements named) to manage the cells table.
	// main cell
	 	//System.out.println("File"); 
	 }
	: (a=cell {
		// if cell is main, set as main. add to dict.
		if (#a.getName().equals("MAIN")) {
			main = #a;
		}
		// else just add to dict.
		CellLib.getInstance().addCellDef(a);
		
	})+;

/* Cells: a definition and name */
cell returns [CellDef r]
 		{
 			r = null; 
 			String cell_type; 
 			StructuralDefinition d;
 		}
 	: #(DEFINITION d=definition cell_type=unit_assignment ) {
 		CellDef def = new CellDef(#cell_type);
	 	def.setStructure(#d);
	 	r = def;
	 };

/* Structural Definition (Lattice): sequence of statements */
definition returns [StructuralDefinition d] {
			Stmt s; 
			d = new StructuralDefinition(); 
			//System.out.println("Construct structural definition.");
		}
	: #(DEFINITION (s=statement {
							/* Add every statement to the definition */
							d.add(s); 
						}
					)+); 

/* Statements within a cell definition: a chain of binds */
statement returns [Stmt r] {
			r = null; 
			BindType c; 
			Block b, d;
			
			java.util.ArrayList<Object> list = new java.util.ArrayList<Object>();
		}
	
		:#(STATEMENT 
			(b=block {
				//System.out.println("STMT 	Block: " + #b);
					list.add(#b);
				} | 
			 c=bind {
			 		//System.out.println("STMT 	Bind: " + #c);
				 	list.add(#c);
			 	}
			 )+
			) {
				/* Give the chain to a Stmt to analyze */
				r = new Stmt(list);
			};

/* Different types of blocks
BLOCK.UNIT, BLOCK.FACETS , BLOCK.UNIT_LISTS, BLOCK.ONE_FACET ,  */
block returns [Block r] { 
			FacetsBlk fleft, fright;
			CellUnit u;
			Block b = r = null;
			r = new UnitListsBlk();
		}
			/* BLOCK.UNIT */
			/* or UNIT_LISTS: list of bindables */
	: #(BLOCK {
			//System.out.println("Block Type: " + #BLOCK.getText());
			r.setType(#BLOCK.getText());
		}
		(
		
		   /* Blocks are just lists of Blocks */
		  (b=block {
				/* add sub-block to block */
				r.add(#b);
   			})+		|
		  
		  /* *********************** */
		  /* In the terminal cases:  */
		  /* *********************** */
		  /* Boils down to:  */
		  
		  // UnitBlk, UnitFacetBlk, FacetsBlk, or UnitListsBlk
          ((u=unit {
					// It's a UnitBlk
					//System.out.println("   adding sub unit to block");
					//System.out.println("UnitBlk");
					r = new UnitBlk();
					r.add(#u);
			} ((fright=facetblock {
						//System.out.println("UnitFacetBlk");
				 		// Actually, it's a UnitFacetBlk
						UnitBlk tmp = (UnitBlk) r;
						r = new UnitFacetBlk();
						((UnitFacetBlk) r).setUnit(tmp);
  				})? |
  				// No, wait, it's REALLY a unit list blk.
				(u = unit {
						//System.out.println("UnitListsBlk");
						r = new UnitListsBlk();
						r.add(#u);
				 })+)
		      )) |
			    						
		/* UNIT_FACET: (.a,b)BLAH(.c,.d) */
		/* TODO: associate the facetblocks with the unit CONTEXTUALIZING them. return bindable block. */
		(fleft=facetblock {
			   			// a simple facetblock
			   			r.add(#fleft);
			   		}
			   		(b=block {
			   				// or may be a unitfacet block
			   				r = new UnitFacetBlk((UnitBlk) #b);
			   				
			   				((UnitFacetBlk) r).setLeft(#fleft); // preserve the left side
			   			}
			   			(fright=facetblock {
			   				// add right facetblock to the unitfacet block
			   				((UnitFacetBlk) r).setRight(#fright);
			   			})? 
			   		)?) //(COMMA b=block {r.add(#b);})+
			   )) {
			   	
			   	// in case of trivial blocks, flatten the structure
			   	Block possible = null;
			   	possible = r.getFirstSubBlock();
			   	if (possible != null) {
			   		r = possible;
			   	}
			   };

/* 	Units are: (CELLTYPE:instance}
                   instancename 
*/
unit returns [CellUnit r] {
			r = null;
		}
	:  (CELLTYPE {
				/* "static" cells */
				//System.out.print("unit: CELLTYPE:" + #CELLTYPE.getText() + " || " );
				
				// RETURN A BINDABLE CELL_DEF. (later, CELL_DEF will gen() to produce a Cell obj)
				
				//r = new run.core.Sout();
				r = new CellUnit(#CELLTYPE.getText()); 
			}
			/* Optionally, named/instanced */
			(NEW INSTANCE {
				//System.out.println( "   [instance: " + #INSTANCE.getText() + "]");
				r.setLabelName(#INSTANCE.getText()); 
			}|
			(STRING {	
				//System.out.println(" unit: String : " + #STRING.getText());
				r.setLabelName(#STRING.getText());
				
				}))? |
		/* Or, instances of cells declared prior */
		(INSTANCE {
				// TODO: an instance resolution
				r = new InstanceRef(#INSTANCE.getText());
			
				//System.out.println("unit: Named instance : " + #INSTANCE.getText());
			}));

/* TODO: a singular facet unit, or a list of facetdefs e.g. ( .a(CELL).b, .c(CELL2).d )  */
facetblock returns [FacetsBlk b] {
			b = null;
			java.util.ArrayList<String> facetList = new java.util.ArrayList<String>();
		}
	: (FACET {
			/* Add facet to list of facets */
			facetList.add(#FACET.getText());
		})+
			{
				b = new FacetsBlk(facetList);
			};

bind returns [BindType r] {
		r=null;
		//System.out.print("\n           Bind:");
	}
	: #(BIND r=bindOp);
bindOp returns [BindType r] { r = null; }
	: BINDTYPE {
		//System.out.println(#BINDTYPE.getText() + "\n");
		r = new BindType(#BINDTYPE.getText()); /* return new bind based on the text: -> or => */
		};

/* Assigning definitions to units */
/* Relate the lattice to a name (TODO) */
unit_assignment returns [String name] {
		name = null;
	}
	: #(BLOCK CELLTYPE) {
		//System.out.println("Structural Definition associated with Unit Assign:" + t.toStringTree());
		name = #CELLTYPE.getText();
	}; 
